package cn.shengchao.examstar.knowledge.shared.service.impl;

import cn.shengchao.examstar.knowledge.domain.entity.KnowledgePoint;
import cn.shengchao.examstar.knowledge.domain.entity.KnowledgePointMastery;
import cn.shengchao.examstar.knowledge.domain.repository.KnowledgePointMasteryRepository;
import cn.shengchao.examstar.knowledge.domain.repository.KnowledgePointRepository;
import cn.shengchao.examstar.knowledge.shared.dto.MasteryAnalysisDTO;
import cn.shengchao.examstar.knowledge.shared.service.KnowledgePointSharedService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 知识点共享服务实现类
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class KnowledgePointSharedServiceImpl implements KnowledgePointSharedService {

    private final KnowledgePointRepository knowledgePointRepository;
    private final KnowledgePointMasteryRepository knowledgePointMasteryRepository;

    @Override
    public List<KnowledgePoint> getKnowledgePointsBySpecificationType(Long specificationTypeId) {
        return knowledgePointRepository.findBySpecificationTypeId(specificationTypeId);
    }

    @Override
    public List<KnowledgePoint> getKnowledgePointsByIds(List<Long> ids) {
        return knowledgePointRepository.getKnowledgePointsByIds(ids);
    }

    @Override
    public KnowledgePoint getKnowledgePointById(Long knowledgePointId) {
        Optional<KnowledgePoint> knowledgePoint = knowledgePointRepository.findById(knowledgePointId);
        return knowledgePoint.orElse(null);
    }

    @Override
    public List<KnowledgePoint> getKnowledgePointsByParentId(Long parentId) {
        return knowledgePointRepository.findByParentId(parentId);
    }

    @Override
    public List<KnowledgePoint> getUserKnowledgePointsBySpecificationType(Long userId, Long specificationTypeId) {
        // 获取类目下所有知识点
        List<KnowledgePoint> knowledgePoints = getKnowledgePointsBySpecificationType(specificationTypeId);
        
        // 获取用户的知识点掌握度信息
        List<KnowledgePointMastery> masteryList = knowledgePointMasteryRepository.findByUserId(userId);
        
        // 将掌握度信息转换为Map，方便查询
        Map<Long, KnowledgePointMastery> masteryMap = masteryList.stream()
            .collect(Collectors.toMap(KnowledgePointMastery::getKnowledgePointId, mastery -> mastery, (a, b) -> a));
        
        // 筛选用户已学习过的知识点
        return knowledgePoints.stream()
            .filter(point -> masteryMap.containsKey(point.getId()))
            .collect(Collectors.toList());
    }
    
    @Override
    public MasteryAnalysisDTO getMasteryAnalysis(Long userId, Long specificationTypeId) {
        // 不指定学习计划ID时，调用带学习计划ID的重载方法，传null表示不限制学习计划
        return getMasteryAnalysis(userId, specificationTypeId, null);
    }
    
    @Override
    public MasteryAnalysisDTO getMasteryAnalysis(Long userId, Long specificationTypeId, Long studyPlanId) {
        log.info("获取用户[{}]在类目[{}]下的知识点掌握度分析，学习计划ID: {}", userId, specificationTypeId, studyPlanId);
        
        // 1. 获取类目下所有知识点
        List<KnowledgePoint> allKnowledgePoints = getKnowledgePointsBySpecificationType(specificationTypeId);
        int totalKnowledgePoints = allKnowledgePoints.size();
        
        // 2. 获取用户的所有掌握度信息
        List<KnowledgePointMastery> allUserMasteries;
        
        if (studyPlanId != null) {
            // 如果指定了学习计划ID，则过滤该计划下的掌握度信息
            allUserMasteries = knowledgePointMasteryRepository.findByStudyPlanId(studyPlanId).stream()
                .filter(mastery -> mastery.getUserId().equals(userId))
                .collect(Collectors.toList());
        } else {
            // 否则获取用户所有掌握度信息
            allUserMasteries = knowledgePointMasteryRepository.findByUserId(userId);
        }
        
        // 3. 筛选出该类目下的掌握度信息
        Map<Long, KnowledgePointMastery> masteryMap = allUserMasteries.stream()
            .collect(Collectors.toMap(KnowledgePointMastery::getKnowledgePointId, mastery -> mastery, (a, b) -> a));
            
        List<KnowledgePointMastery> categoryMasteries = allKnowledgePoints.stream()
            .map(KnowledgePoint::getId)
            .filter(masteryMap::containsKey)
            .map(masteryMap::get)
            .collect(Collectors.toList());
            
        int learnedKnowledgePoints = categoryMasteries.size();
        
        // 4. 计算掌握度分布
        Map<String, Integer> masteryDistribution = categoryMasteries.stream()
                .peek(item->{
                    if(item.getDegreeOfMastery()==null){
                        item.setDegreeOfMastery("N");
                    }
                    if(item.getAccuracyRate()==null){
                        item.setAccuracyRate("0");
                    }
                })
            .collect(Collectors.groupingBy(
                KnowledgePointMastery::getDegreeOfMastery, 
                Collectors.summingInt(mastery -> 1)
            ));
            
        // 确保所有等级都有值
        masteryDistribution.putIfAbsent("S", 0);
        masteryDistribution.putIfAbsent("A", 0);
        masteryDistribution.putIfAbsent("B", 0);
        masteryDistribution.putIfAbsent("C", 0);
        
        // 5. 计算总体掌握度
        double overallMasteryPercentage = calculateOverallMasteryPercentage(masteryDistribution, totalKnowledgePoints);
        String overallMasteryLevel = determineMasteryLevel(overallMasteryPercentage);
        
        // 6. 获取最薄弱的知识点
        List<MasteryAnalysisDTO.WeakKnowledgePoint> weakestPoints = findWeakestPoints(categoryMasteries, allKnowledgePoints, 3);

        // 8. 构建并返回分析DTO
        return MasteryAnalysisDTO.builder()
            .overallMasteryPercentage(overallMasteryPercentage)
            .overallMasteryLevel(overallMasteryLevel)
            .totalKnowledgePoints(totalKnowledgePoints)
            .learnedKnowledgePoints(learnedKnowledgePoints)
            .weakestPoints(weakestPoints)
            .masteryDistribution(masteryDistribution)
            .studyPlanId(studyPlanId)
            .build();
    }
    
    /**
     * 计算总体掌握度百分比
     */
    private double calculateOverallMasteryPercentage(Map<String, Integer> masteryDistribution, int totalPoints) {
        if (totalPoints == 0) return 0;
        
        // 各等级的权重
        double sWeight = 1.0;
        double aWeight = 0.8;
        double bWeight = 0.6;
        double cWeight = 0.3;
        
        int sCount = masteryDistribution.getOrDefault("S", 0);
        int aCount = masteryDistribution.getOrDefault("A", 0);
        int bCount = masteryDistribution.getOrDefault("B", 0);
        int cCount = masteryDistribution.getOrDefault("C", 0);
        
        // 计算加权得分
        double totalScore = (sCount * sWeight + aCount * aWeight + bCount * bWeight + cCount * cWeight) * 100;
        
        // 计算已学习知识点总数
        int learnedPoints = sCount + aCount + bCount + cCount;
        
        // 计算已学习知识点的平均得分
        double learnedPointsPercentage = learnedPoints > 0 ? totalScore / learnedPoints : 0;
        
        // 考虑学习覆盖率
        double coverageRate = (double) learnedPoints / totalPoints;
        
        // 综合得分 = 已学习知识点平均得分 * 学习覆盖率
        return learnedPointsPercentage * coverageRate;
    }
    
    /**
     * 确定掌握度等级
     */
    private String determineMasteryLevel(double masteryPercentage) {
        if (masteryPercentage >= 90) {
            return "S"; // 精通
        } else if (masteryPercentage >= 75) {
            return "A"; // 掌握
        } else if (masteryPercentage >= 60) {
            return "B"; // 理解
        } else {
            return "C"; // 初步了解
        }
    }
    
    /**
     * 查找最薄弱的知识点
     */
    private List<MasteryAnalysisDTO.WeakKnowledgePoint> findWeakestPoints(
            List<KnowledgePointMastery> masteries, 
            List<KnowledgePoint> allPoints, 
            int limit) {
        
        // 创建知识点ID到知识点的映射
        Map<Long, KnowledgePoint> pointsMap = allPoints.stream()
            .collect(Collectors.toMap(KnowledgePoint::getId, point -> point));
            
        // 按掌握度等级排序，C最弱，S最强
        List<KnowledgePointMastery> sortedMasteries = new ArrayList<>(masteries);
        sortedMasteries.sort(Comparator.comparing(mastery -> {
            switch (mastery.getDegreeOfMastery()) {
                case "C": return 1;
                case "B": return 2;
                case "A": return 3;
                case "S": return 4;
                default: return 0;
            }
        }));
        
        // 取前N个最薄弱的知识点
        return sortedMasteries.stream()
            .limit(limit)
            .map(mastery -> {
                KnowledgePoint point = pointsMap.get(mastery.getKnowledgePointId());
                String name = point != null ? point.getName() : "未知知识点";
                
                double masteryPercentage = calculateMasteryPercentage(mastery.getDegreeOfMastery());
                
                return MasteryAnalysisDTO.WeakKnowledgePoint.builder()
                    .id(mastery.getKnowledgePointId())
                    .name(name)
                    .masteryPercentage(masteryPercentage)
                    .masteryLevel(mastery.getDegreeOfMastery())
                    .learningCount(0) // 这里可以扩展，从学习记录中获取学习次数
                    .studyTimeMinutes(0) // 这里可以扩展，从学习记录中获取学习时长
                    .build();
            })
            .collect(Collectors.toList());
    }
    
    /**
     * 根据掌握度等级计算百分比
     */
    private double calculateMasteryPercentage(String degreeOfMastery) {
        switch (degreeOfMastery) {
            case "S": return 95.0;
            case "A": return 80.0;
            case "B": return 65.0;
            case "C": return 40.0;
            default: return 0.0;
        }
    }

} 